package com.rk.app.poll.client.template.polls;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
import com.google.gwt.user.datepicker.client.DateBox;
import com.rk.app.poll.client.Poll;
import com.rk.app.poll.client.PollService;
import com.rk.app.poll.client.PollServiceAsync;

public class SimplePoll extends Composite {
	private final PollServiceAsync pollingService = GWT.create(PollService.class);

	private VerticalPanel mainPanel = new VerticalPanel();

	private FlexTable pollFlexTable = new FlexTable();

	private TextArea question = new TextArea();

	private TextArea optionText = new TextArea();

	private DateBox startOnText = new DateBox();

	private DateBox endsOnText = new DateBox();

	public SimplePoll() {

		int row = -1;
		FlexCellFormatter cellFormatter = pollFlexTable.getFlexCellFormatter();
		cellFormatter.setWidth(++row, 0, "20%");

		// pollFlexTable.setBorderWidth(2);
		pollFlexTable.setWidth("100%");

		pollFlexTable.setText(row, 0, "Poll Text");
		question.setWidth("100%");
		pollFlexTable.setWidget(row, 1, question);
		cellFormatter.setColSpan(row, 1, 2);

		pollFlexTable.setText(++row, 0, "Poll Start On");

		pollFlexTable.setWidget(row, 1, startOnText);
		pollFlexTable.setText(++row, 0, "Poll Ends On");

		pollFlexTable.setWidget(row, 1, endsOnText);

		pollFlexTable.setText(++row, 0, "Option");

		optionText.setWidth("100%");
		pollFlexTable.setWidget(row, 1, optionText);
		Button optionAddButton = new Button("Add");
		optionAddButton.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {
				addRow(pollFlexTable, optionText.getText());
			}

		});
		pollFlexTable.setWidget(row, 2, optionAddButton);

		ScrollPanel scroller = new ScrollPanel(pollFlexTable);
		mainPanel.setWidth("100%");
		mainPanel.add(scroller);

		HorizontalPanel commandPanel = new HorizontalPanel();
		commandPanel.setSpacing(5);
		Button save = new Button("Save");
		save.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				savePoll();
			}
		});
		Button reset = new Button("Reset");
		reset.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				resetPoll();
			}
		});
		commandPanel.add(reset);
		commandPanel.add(save);

		HorizontalPanel panel = new HorizontalPanel();
		panel.setWidth("100%");
		panel.setBorderWidth(1);
		panel.setHorizontalAlignment(HorizontalPanel.ALIGN_CENTER);
		panel.add(commandPanel);
		panel.setStyleName("formCommandPanel");

		mainPanel.add(panel);
		mainPanel.setBorderWidth(1);
		mainPanel.setStyleName("formPanel");
		initWidget(mainPanel);
	}

	private void savePoll() {
		final List<HTML> messages = new ArrayList<HTML>();
		List<String> validOptions = new ArrayList<String>();
		String s = question.getText();
		if (s == null || s.trim().equals("")) {
			HTML msg = new HTML("<p><b>Poll Text</b> can't be empty.</p>");
			msg.setStyleName("errorMessage");
			messages.add(msg);
		}
		Date sd = startOnText.getValue();
		if (sd == null) {
			HTML msg = new HTML("<p><b>Poll Start On</b> date can't be left blank.</p>");
			msg.setStyleName("errorMessage");
			messages.add(msg);
		}
		Date ed = endsOnText.getValue();
		if (ed == null) {
			HTML msg = new HTML("<p><b>Poll Start On</b> date can't be left blank.</p>");
			msg.setStyleName("errorMessage");
			messages.add(msg);
		}
		if (sd != null && ed != null) {
			if (sd.after(ed)) {
				HTML msg = new HTML("<p><b>Poll Start On</b> date should be before [<i>Poll Ends On</i>] date.</p>");
				msg.setStyleName("errorMessage");
				messages.add(msg);
			}
		}
		int optCount = pollFlexTable.getRowCount();
		if (optCount > 4) {
			Set<String> items = new HashSet<String>();
			for (int i = 4; i < optCount; i++) {
				RadioButton button = (RadioButton) pollFlexTable.getWidget(i, 1);
				String t = button.getText();
				validOptions.add(t);
				if (!items.add(t.trim().toLowerCase())) {
					HTML msg = new HTML("<p><b>Option</b> should be unique,[<i>" + t
							+ "</i>] matches with at least one option</p>");
					msg.setStyleName("errorMessage");
					messages.add(msg);
					break;
				}
			}
		} else {
			HTML msg = new HTML("<p><b>Option</b> should be at least 2 in numbers.</p>");
			msg.setStyleName("errorMessage");
			messages.add(msg);
		}
		if (!messages.isEmpty()) {
			DialogBox dialogBox = createDialogBox("Errors", messages);
			dialogBox.center();
			dialogBox.show();
		} else {
			Poll poll = new Poll();
			poll.setPollQuestion(s);
			poll.setStartsOn(sd);
			poll.setEndsOn(ed);
			poll.setChoices(validOptions.toArray(new String[0]));
			pollingService.savePoll(poll, new AsyncCallback<String>() {
				public void onFailure(Throwable caught) {
					messages.add(new HTML("Error occurred while saving"));
					messages.add(new HTML(caught.getLocalizedMessage()));
					showDialog("Error", messages);
				}

				public void onSuccess(String result) {
					messages.add(new HTML("Poll is saved successfully with id [<b>" + result + "</b>]."));
					messages.add(new HTML("You may keep on adding more polls."));
					showDialog("Success", messages);
				}
			});

		}
	}

	private void showDialog(String title, List<HTML> messages) {
		DialogBox dialogBox = createDialogBox(title, messages);
		dialogBox.center();
		dialogBox.show();
	}

	private void resetPoll() {
		question.setText("");
		startOnText.setValue(null, false);
		endsOnText.setValue(null, false);
		optionText.setText("");
		while (pollFlexTable.getRowCount() > 4) {
			pollFlexTable.removeRow(4);
		}
	}

	/**
	 * Add a row to the flex table.
	 */
	private void addRow(FlexTable flexTable, String text) {
		final int numRows = flexTable.getRowCount();
		final RadioButton rb = new RadioButton("option", text);
		Anchor removeButton = new Anchor("Remove");
		removeButton.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {
				removeRow(pollFlexTable, rb);
			}

		});
		flexTable.setWidget(numRows, 0, removeButton);
		flexTable.setWidget(numRows, 1, rb);
		flexTable.getFlexCellFormatter().setColSpan(numRows, 1, 2);

	}

	/**
	 * Remove a row from the flex table.
	 */
	private void removeRow(FlexTable flexTable, RadioButton rb) {
		int numRows = flexTable.getRowCount();
		for (int i = numRows; i > 2; i--) {
			Widget w = flexTable.getWidget(i - 1, 1);
			if (rb == w) {
				flexTable.removeRow(i - 1);
				break;
			}
		}
	}

	private DialogBox createDialogBox(String title, List<HTML> messages) {
		// Create a dialog box and set the caption text
		final DialogBox dialogBox = new DialogBox();
		dialogBox.setText(title);

		// Create a table to layout the content
		VerticalPanel dialogContents = new VerticalPanel();
		dialogContents.setSpacing(4);
		dialogBox.setWidget(dialogContents);
		for (int i = 0; i < messages.size(); i++) {
			// Add some text to the top of the dialog
			dialogContents.add(messages.get(i));
			// dialogContents.add(new HTML("<p>&nbsp;</p>"));
		}

		// Add a close button at the bottom of the dialog
		Button closeButton = new Button("Close", new ClickHandler() {
			public void onClick(ClickEvent event) {
				dialogBox.hide();
			}
		});
		dialogContents.add(closeButton);

		// Return the dialog box
		return dialogBox;
	}
}
